package tests;

import java.io.*;

import index.ColumnIndexScan;
import index.IndexException;
import iterator.*;

import iterator.CondExpr;

import iterator.FldSpec;

import iterator.RelSpec;

import java.io.*;

import java.util.*;
import java.lang.*;
import heap.*;
import bitmap.BMFileScan;
import bitmap.BitMapFile;
import bufmgr.*;
import diskmgr.*;
import global.*;
import chainexception.*;
import btree.*;

import columnar.*;

public class Query implements GlobalConst {

	/*
	 * constructor for all parameters - datafilename , coulmnDBname, columnar
	 * filename , numcolumns
	 */
	public String datafilename, cdbname, filename;
	public int numcolumns;
	public TID[] tidArr;
	ColumnarFile _cf;
	//int[] colnosg;
	int[] attrtypesg;
	int[] target_colnums;
	int[] target_attr;

	public Query() {
	}

	

	public void runTest1(String cdbname, String Colfilename, String cname,
			String[] targetcolname, String operator, String value,
			String accesstype,int numbuf) throws IOException

	{
		try
		{
			String dbpath = cdbname;
			String record;

	int  targetnum, nocol;
	Scanner sc = new Scanner(System.in);
	SystemDefs sysdef = new SystemDefs(dbpath, 0, numbuf, "Clock");

		PCounter.initialize();
		this.filename = Colfilename;
		int i = 0, z = 0;
		
		BufferedReader br = new BufferedReader(new FileReader("/tmp/"+Colfilename+".hdr"));

		while ((record = br.readLine()) != null) {
			z++;
		}
		this.numcolumns = z;
		int[] colnos = new int[this.numcolumns];
		int[] attrtypes = new int[this.numcolumns];
		// all colnames, colnumbers and attr by parsing the name.hdr
		String[] colnames = new String[this.numcolumns];
		
		int condn_columnno = -1, condn_attrType = -1;
		String condn_columnname = " ";
		// target column number and attr
		
		
		// read from name.hdr
		BufferedReader br4 = new BufferedReader(new FileReader("/tmp/"+Colfilename+".hdr"));

		while ((record = br4.readLine()) != null) {

			StringTokenizer st4 = new StringTokenizer(record, "\t");

			while (st4.hasMoreTokens()) {
				StringTokenizer st5 = new StringTokenizer(st4.nextToken(), " ");
				String colName = st5.nextToken().trim();
				colnames[i] = colName;
				int colNum = Integer.parseInt(st5.nextToken().trim());
				colnos[i] = colNum;
				int attrType = Integer.parseInt(st5.nextToken().trim());
				attrtypes[i] = attrType;

				if (colName.equals(cname)) {
					condn_columnno = colNum;
					condn_attrType = attrType;
					condn_columnname = colName;

				}

			}

			i++;

		}
		
		 target_colnums= new int[targetcolname.length];
		 target_attr= new int[targetcolname.length];
		int ch=0; 
//		for(int p=0;p<targetcolname.length;p++)
//			if(targetcolname[p]==)
		for (int p=0;p<targetcolname.length;p++)
		{
		  for(int k=0;k<numcolumns;k++)
		  {
			  
		    if(targetcolname[p].equals(colnames[k]))
		    {
		    	target_attr[p]= attrtypes[k];
		    	target_colnums[p]=k+1;
		    	ch++;    	
		    }
		}
		}

		if(ch!=targetcolname.length)
		{
		 System.out.println("invalid Colname"+ch);
		 System.exit(0);
		}
 

		// ---------------------------- diff access types cases
		// -----------------------
		// BTree
		if (accesstype.equalsIgnoreCase("BTree")) {
			System.out.println("Btree check");

			// bi.indexTest("cdbname","hpfile","A","BTree");

			CondExpr[] outFilter = new CondExpr[2];
			outFilter[0] = new CondExpr();
			outFilter[0].op = new AttrOperator(AttrOperator.aopEQ);
			outFilter[0].next = null;
			outFilter[0].type1 = new AttrType(AttrType.attrSymbol);
			if (condn_attrType == 1)
				outFilter[0].type2 = new AttrType(AttrType.attrInteger);
			else
				outFilter[0].type2 = new AttrType(AttrType.attrString);
			outFilter[0].operand1.symbol = new FldSpec(new RelSpec(
					RelSpec.outer), 1); // col num ?
			// check datatype of attribute against meta data file
			if (condn_attrType == 1)
				outFilter[0].operand2.integer = Integer.parseInt(value); // datavalue
			else
				outFilter[0].operand2.string = value; // datavalue
			outFilter[1] = null;

			AttrType[] Fstypes = new AttrType[this.numcolumns];
			AttrType[] Stypes = new AttrType[1]; // one attribute

			if (condn_attrType == 1)
				Stypes[0] = new AttrType(AttrType.attrInteger);
			else
				Stypes[0] = new AttrType(AttrType.attrString);
			int j = 0;
			for (int cou = 0; cou < this.numcolumns; cou++) {
				if (attrtypes[cou] == 0)
					j++;
			}
			short[] Ssizes = new short[j];
			for (int cou = 0, k = 0; cou < numcolumns; cou++) {
				if (attrtypes[cou] == 0) {
					Fstypes[cou] = new AttrType(AttrType.attrString);
					Ssizes[k] = strlen;
					k++;
				} else
					Fstypes[cou] = new AttrType(AttrType.attrInteger);
			}
			int numfields_input = 1; // no. of fields in input tuple
			int numfields_output = 1; // no. of fields in output - take from
										// target column names
			FldSpec[] Sprojection = new FldSpec[1];
			// find what fields are required and construct corresponding
			// projection
			Sprojection[0] = new FldSpec(new RelSpec(RelSpec.outer), 1); // order
																			// of
																			// fields
			ColumnIndexScan ciscan = null;
			String columnarfilename = filename + (condn_columnno - 1);
			String indexfilename = "Btree" + filename + (condn_columnno - 1);
			try {
				ciscan = new ColumnIndexScan(new IndexType(IndexType.B_Index),
						columnarfilename, indexfilename, Stypes, Ssizes,
						numfields_input, numfields_output, Sprojection,
						outFilter, 1, true, attrtypesg);

			} catch (Exception e) {
				System.out.println("In Btree Index Scan" + e);
			}
			Tuple t = new Tuple();
			try {
				while ((t = ciscan.get_next()) != null) {
					System.out.println("got records in BTree Index scan");
					t.print(Fstypes);
				}
			} catch (Exception e) {
				System.err.println("" + e);
				e.printStackTrace();
			}

		}
		//bitmap
		else if (accesstype.equalsIgnoreCase("BitMap"))
		{
			System.out.println("BitMap check");

			// bi.indexTest("cdbname","hpfile","A","BTree");

			CondExpr[] outFilter = new CondExpr[1];
			outFilter[0] = null;
//			outFilter[1] = null;

			AttrType[] Fstypes = new AttrType[this.numcolumns];
			AttrType[] Stypes = new AttrType[1]; // one attribute

			if (condn_attrType == 1)
				Stypes[0] = new AttrType(AttrType.attrInteger);
			else
				Stypes[0] = new AttrType(AttrType.attrString);
			int j = 0;
			for (int cou = 0; cou < this.numcolumns; cou++) {
				if (attrtypes[cou] == 0)
					j++;
			}
			short[] Ssizes = new short[j];
			for (int cou = 0, k = 0; cou < numcolumns; cou++) {
				if (attrtypes[cou] == 0) {
					Fstypes[cou] = new AttrType(AttrType.attrString);
					Ssizes[k] = strlen;
					k++;
				} else
					Fstypes[cou] = new AttrType(AttrType.attrInteger);
			}
			int numfields_input = 4; // no. of fields in input tuple
			int numfields_output = 1; // no. of fields in output - take from
										// target column names
			FldSpec[] Sprojection = new FldSpec[1];
			// find what fields are required and construct corresponding
			// projection
			Sprojection[0] = new FldSpec(new RelSpec(RelSpec.outer), 1); // order
																			// of
									// fields
		BitMapFile bmf ;	
		BMFileScan bitmapFileScan;
		String bitmapfilename = "BitMapIndex_" + condn_columnno + "_" + value;
	    	bmf = new BitMapFile(bitmapfilename);
	    	bitmapFileScan = bmf.new_scan();
	    	
	    	  KeyDataEntry nextentry = null;

	    	  
	    		  try {
			    	    	
			      nextentry = bitmapFileScan.get_next();
			    }
			    catch (Exception e) {
			      throw new IndexException(e, "IndexScan.java: BitMap error");
			    }	  
			    		    
			      // not index_only, need to return the whole tuple
			      //rid = ((LeafData)nextentry.data).getData();
			    while(nextentry.position != -1)
		    	  {
			    int position = 0; 	
			    position = nextentry.position; 
		        if (position != -1)
		        {
			    Tuple tfin = new Tuple();
			    	  //int position = f._findPosforRID(rid);
			    	  PositionScan ps = new PositionScan(filename, attrtypesg);
			    	  tfin = ps.returnTuple(position);
				      tfin.print(Fstypes);
			      }
			      nextentry = bitmapFileScan.get_next();
			    
	    	  }
//			ColumnIndexScan ciscan = null;
//			String columnarfilename = filename + (condn_columnno - 1);
//		
//			String bitmapfilename = "BitMapIndex_" + condn_columnno + "_" + value;
//			try {
//				ciscan = new ColumnIndexScan(new IndexType(IndexType.Bitmap),
//						columnarfilename, bitmapfilename, Fstypes, Ssizes,
//						numfields_input, numfields_output, Sprojection,
//						outFilter, 1, true, attrtypesg);
//
//			} catch (Exception e) {
//				System.out.println("In Bitmap Index Scan" + e);
//			}
//			Tuple t = new Tuple();
//			try {
//				while ((t = ciscan.get_next()) != null) {
//					System.out.println("got records in Bitmap Index scan");
//					t.print(Fstypes);
//				}
//			} catch (Exception e) {
//				System.err.println("" + e);
//				e.printStackTrace();
//			}
		}
		// FileScan
		else if (accesstype.equalsIgnoreCase("Filescan")) {
			System.out.println("FileScan check");

			CondExpr[] outFilter = new CondExpr[2];
			outFilter[0] = new CondExpr();
			outFilter[0].op = new AttrOperator(AttrOperator.aopEQ);
			outFilter[0].next = null;
			outFilter[0].type1 = new AttrType(AttrType.attrSymbol);

			if (condn_attrType == 1)
				outFilter[0].type2 = new AttrType(AttrType.attrInteger);
			else
				outFilter[0].type2 = new AttrType(AttrType.attrString);
			outFilter[0].operand1.symbol = new FldSpec(new RelSpec(
					RelSpec.outer), condn_columnno-1);
			// check datatype of attribute against meta data file
			if (condn_attrType == 1)
				outFilter[0].operand2.integer = Integer.parseInt(value); // datavalue
			else
				outFilter[0].operand2.string = value; // datavalue

			outFilter[1] = null;

			Tuple t = new Tuple();
			AttrType[] Stypes  = new AttrType[numcolumns];
			
			
			if (condn_attrType == 1)
				Stypes[0] = new AttrType(AttrType.attrInteger);
			else
				Stypes[0] = new AttrType(AttrType.attrString);

			// short [] Fssizes = new short[2];
			int j = 0;
			
			for (int cou = 0; cou < this.numcolumns; cou++) {
				if (attrtypes[cou] == 0)
				{
					Stypes[cou] =new AttrType(AttrType.attrString);
					j++;}
					else
						Stypes[cou] =new AttrType(AttrType.attrInteger);	
			}
			

			//sri
			
			
			short[] Ssizes = new short[j];
			for(int k=0;k<j;k++)
				Ssizes[k] = strlen;
			
           //sri
			//fields to be projected i.e... target column names
			FldSpec[] Sprojection = new FldSpec[target_colnums.length];
			// find what fields are required and construct corresponding
			// projection
			//sri
			AttrType[] Fstypes = new AttrType[target_colnums.length];
			  int msize = 0;
			  //msize - the number of strings in the target column names
			  //set the projections for the respective relations
			for(int p=0;p<target_colnums.length;p++)
			{  
				if(target_attr[p]==0)
				{
				Fstypes[p] =new AttrType(AttrType.attrString);
				msize++;
				}
				else
				{
					Fstypes[p] =new AttrType(AttrType.attrInteger);
				
				}
				Sprojection[p] = new FldSpec(new RelSpec(RelSpec.outer),target_colnums[p] );
			}    
			short[] Fssize = new short[msize];
			for(int k=0;k<msize;k++)
				Fssize[k] = strlen;
			
			//sri
			// no. of fields in input tuple
			short numfields_input = 4; 
			// no. of fields in output 
			short numfields_output =(short)target_colnums.length; 
			//short numfields_output =1;
			// Stypes - attrtypes of all attributes for a columnar file
			//Ssize - strings len for all attributes for a columnar file
			//numfields_input - all columns , output- target columns count
			//Fstypes - attr type of target col, Fssize - string len for target col's
			FileScan fs = null;
			try {
				String columnarfilename = this.filename;// / construct the file name
													// based on column no.
				fs = new FileScan(columnarfilename, Stypes, Ssizes,
						numfields_input, numfields_output, Sprojection,
						outFilter,target_colnums, Fstypes, Fssize);
			}

			catch (Exception e) {
				System.err.println("" + e);
			}

			try {
				System.out.println("Records in Filescan.");
				while ((t = fs.get_next()) != null) {
						t.print(Fstypes);
				}
			} catch (Exception e) {
				System.err.println("" + e);
				e.printStackTrace();
			}
		}
		// ColumnFileScan
		else if (accesstype.equalsIgnoreCase("ColumnFilescan")) {
			// //column scan
			System.out.println(" Column File Scan testing");
			// write conditional expression matching the query
			CondExpr[] outFilter = new CondExpr[2];
			outFilter[0] = new CondExpr();
			outFilter[0].op = new AttrOperator(AttrOperator.aopEQ);
			outFilter[0].next = null;
			outFilter[0].type1 = new AttrType(AttrType.attrSymbol);

			if (condn_attrType == 1)
				outFilter[0].type2 = new AttrType(AttrType.attrInteger);
			// //else if string
			else
				outFilter[0].type2 = new AttrType(AttrType.attrString);
			outFilter[0].operand1.symbol = new FldSpec(new RelSpec(
					RelSpec.outer), 1);
			// check datatype of attribute against meta data file
			// if attribute is string
			if (condn_attrType == 1)
				outFilter[0].operand2.integer = Integer.parseInt(value); // datavalue
			else
				outFilter[0].operand2.string = value; // datavalue

			outFilter[1] = null;

			Tuple t = new Tuple();

			AttrType[] Stypes = new AttrType[1]; // one attribute
			AttrType[] Fstypes = new AttrType[this.numcolumns];

			if (condn_attrType == 1)
				Stypes[0] = new AttrType(AttrType.attrInteger);
			else
				Stypes[0] = new AttrType(AttrType.attrString);

			short[] Ssizes = new short[1];

			for (int cou = 0; cou < numcolumns; cou++) {
				if (attrtypes[cou] == 0) {
					Fstypes[cou] = new AttrType(AttrType.attrString);
					Ssizes[0] = strlen;
				} else
					Fstypes[cou] = new AttrType(AttrType.attrInteger);
			}

			FldSpec[] Sprojection = new FldSpec[1];
			// find what fields are required and construct corresponding
			// projection
			Sprojection[0] = new FldSpec(new RelSpec(RelSpec.outer), 1); // order
																			// of
																			// fields

			short numfields_input = 1; // no. of fields in input tuple
			short numfields_output = 1; // no. of fields in output - take from
										// target column names

			ColumnarFileScan cfs = null;
			try {
				String columnarfilename_attribute = this.filename
						+ (condn_columnno - 1);// / construct the file name
												// based on column no.
				cfs = new ColumnarFileScan(columnarfilename_attribute, Stypes,
						Ssizes, numfields_input, numfields_output, Sprojection,
						outFilter, attrtypesg);
			}

			catch (Exception e) {
				System.err.println("" + e);
			}
			try {
				while ((t = cfs.get_next()) != null) {

					t.print(Fstypes);
				}
			} catch (Exception e) {
				System.err.println("" + e);
				e.printStackTrace();
			}
		}
		else if(accesstype.equalsIgnoreCase("delete"))
		{
			RID rid = new RID();
			Heapfile hf[] = new Heapfile[this.numcolumns];
			Scan scan[] = new Scan[this.numcolumns];
			for(int m =0 ; m<this.numcolumns ; m++)
			{
				hf[m] = new Heapfile(this.filename+ m);
				System.out.println(this.filename+ m);
			}
			for(int m =0 ; m<this.numcolumns ; m++)
			{
				scan[m] = new Scan(hf[m]);
				
			}
			int pos=-1;
			while(scan[condn_columnno].getNext(rid)!=null)
			{
				boolean recordDeleted= false;
				
				Tuple t1 = new Tuple();
				AttrType[] at = new AttrType[1];
				short[] tsize1 = new short[1];
				if(condn_attrType == 0)
				{
				at[0] = new AttrType(AttrType.attrString);
				tsize1[0] = strlen;
				}
				else
				 at[0] = new AttrType(AttrType.attrInteger);
				

				t1.setHdr((short) 1, at, tsize1);
				// t.getStrFld(1,data[i]);

				Tuple tup1 = new Tuple(t1.size());
				tup1.setHdr((short) 1, at, tsize1);
				tup1 = hf[condn_columnno].getRecord(rid);
				t1.tupleCopy(tup1);
				System.out.println(t1.getIntFld( 1));
				
				if(t1.getIntFld( 1)== Integer.parseInt(value))
				{
					hf[condn_columnno].deleteRecord(rid);
					recordDeleted = true;
				}
			//	RID rtemp = new RID();
				for(int n=0;n<this.numcolumns;n++)
				{
					if(n!= condn_columnno)
					{
						if(scan[n].getNext(rid)!= null)
						{
							if(	recordDeleted == true)
							{
								hf[n].deleteRecord(rid);
							}
						}
					}
				}
			
			}
		}
		}
		
		catch (Exception e) {
			System.out.println(e.getMessage());
		} finally {
			try {
				// IntegerValue vc = new IntegerValue(new Integer(1));
				// cf.createBitMapIndex(2, (ValueClass)vc);
				// for(i=0;i<this.tidArr.length;i++)
				// cf.getTuple(this.tidArr[i]);
				// cf.markTupleDeleted(tid);
				// cf.purgeAllDeletedTuples();
				SystemDefs.JavabaseBM.unpinAllPages();
				SystemDefs.JavabaseBM.flushAllPages();
				System.out.println("Number of Pages Read: " + PCounter.rcounter);
				System.out.println("Number of Pages Written: "
						+ PCounter.wcounter);
			} catch (Exception e) {
			}
		}


	}

	public static void main(String args[]) throws IOException, HFException,
			HFBufMgrException, HFDiskMgrException {
		String cdbname = "/tmp/cdbname";
		Query qu = new Query();
				//String[] target = new String[4];
		Scanner sc= new Scanner(System.in);
		  System.out.println("Enter the target columns in the format colname1:colname2:..");
		   String  token=sc.next();
		   String delims = "[:]+";
		
		   String[] target = token.split(delims);  
		
		   System.out.println("lenght"+target.length);
		   
		 
			   System.out.println("Enter the constraint column name");
		     String col = sc.next();
			   System.out.println("Enter the constraint column value");
			     String value = sc.next();
			     System.out.println("Enter the access type bitmap/btree/filescan/columnfilescan/");
			     String access = sc.next();
			     System.out.println("Enter the buffer pool size");
				   int numbuf = sc.nextInt();
		    qu.runTest1(cdbname,"hpfile", col, target, "=", value, access,numbuf);

	//	qu.runTest1(cdbname,"hpfile", "A", target, "=", "West_Virginia", "filescan");

	}
}